/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: 西安华信智慧数字科技有限公司
 * 系统版本: 1.0.0
 * 开发人员: zhangfb
 * 开发时间: 2019/11/30 14:05
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.hyacinth.cloudnote.common.security;

import com.hyacinth.cloudnote.common.exception.AppRuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.security.MessageDigest;
import java.util.Objects;

/**
 * MD5密码编码器
 *
 * @author zhangfb
 * @version 1.0.0.1
 * @since 2019/11/30 14:05
 */
@Slf4j
public class MD5PasswordEncoder implements PasswordEncoder {

    private static final String PASSWORD_SALT_DELIMITER = "$";

    /**
     * 密码加密（pwd+"$"+salt）
     *
     * @param rawPassword 密码加盐不合法
     * @return 加密后的密码
     */
    @Override
    public String encode(CharSequence rawPassword) {
        if (StringUtils.contains(rawPassword, PASSWORD_SALT_DELIMITER)) {
            // 截取盐
            String[] pwdSalt = StringUtils.split(String.valueOf(rawPassword), "$");
            if (pwdSalt.length < 2) {
                throw new AppRuntimeException("raw password is is illegal");
            }
            return encodePassword(pwdSalt[0], pwdSalt[1]);
        }
        return encodePassword(String.valueOf(rawPassword));
    }

    /**
     * 校验密码是否匹配
     *
     * @param rawPassword     用户输入密码pwd+"$"+salt
     * @param encodedPassword 加密后的密码（从数据库中取）
     * @return true | false
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        if (StringUtils.isBlank(encodedPassword)) {
            log.error("encoded password is empty");
            return false;
        }
        if (StringUtils.contains(rawPassword, PASSWORD_SALT_DELIMITER)) {
            // 截取盐
            String[] pwdSalt = StringUtils.split(String.valueOf(rawPassword), "$");
            if (pwdSalt.length < 2) {
                log.error("raw password is is illegal");
                return false;
            }
            return Objects.equals(encodedPassword, encodePassword(pwdSalt[0], pwdSalt[1]));
        }
        return Objects.equals(encodedPassword, encodePassword(String.valueOf(rawPassword)));
    }

    /**
     * 密码加密, 不带盐
     *
     * @param password 密码
     * @return 密码加密串
     */
    private String encodePassword(String password) {
        return encodePassword(password, null);
    }

    /**
     * 密码加密
     *
     * @param password 密码
     * @param salt     盐
     * @return 密码加密串
     */
    private String encodePassword(String password, String salt) {
        if (null == password) {
            log.error("raw password is empty");
            return null;
        }

        byte[] sourceBytes = password.getBytes();

        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.reset();
            if (StringUtils.isNotBlank(salt)) {
                // 加盐操作
                byte[] saltBytes = salt.getBytes();
                digest.update(saltBytes);
            }
            byte[] hashed = digest.digest(sourceBytes);

            digest.reset();
            hashed = digest.digest(hashed);

            return new String(Hex.encode(hashed));

        } catch (Exception e) {
            log.error("encode password error", e);
            return null;
        }
    }
}
